home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume15 / lp-onionskin < prev    next >
Encoding:
Internet Message Format  |  1988-05-24  |  9.6 KB

  1. Subject:  v15i009:  Wrapper for System V lp, bug work-around
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: utgpu!utfyzx!harrison (David Harrison)
  7. Posting-number: Volume 15, Issue 9
  8. Archive-name: lp-onionskin
  9.  
  10. Here is a small program of use only for systems with the System V 
  11. semaphore facility.  It works around a bug in the lockfile mechanism 
  12. of lp(1) that causes the spooler to periodically crash if it gets 
  13. 2 or more jobs at almost the same time.  The README file discusses 
  14. further.  To do the job right would nuke the lockfiles in lp(1)
  15. in favour of the System V ipcs facility, but that requires source
  16. (which I have) and time (which I don't have), so this is just
  17. an onionskin around lp(1).
  18.     David Harrison, Dept. of Physics, Univ. of Toronto
  19.     {ihnp4,utzoo}!utgpu!utfyzx!harrison
  20.  
  21. #! /bin/sh
  22. # This is a shell archive, meaning:
  23. # 1. Remove everything above the #! /bin/sh line.
  24. # 2. Save the resulting text in a file.
  25. # 3. Execute the file with /bin/sh (not csh) to create the files:
  26. #    Makefile
  27. #    README
  28. #    lp.c
  29. #    lock.c
  30. export PATH; PATH=/bin:$PATH
  31. echo shar: extracting "'Makefile'" '(435 characters)'
  32. if test -f 'Makefile'
  33. then
  34.     echo shar: will not over-write existing file "'Makefile'"
  35. else
  36. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  37. X#    @(#)Makefile    1.1 U of T Physics 2/24/88
  38. X
  39. XSRC = lp.c lock.c
  40. XOBJS = lp.o lock.o
  41. XBIN = /usr/bin
  42. XLP = lp -s
  43. XLINTFLAGS = -DLINT
  44. X
  45. X# for symbolic debugger
  46. X# CFLAGS = -g
  47. X# CDBOBJ = /usr/lib/end.o
  48. X
  49. Xlptry:    $(OBJS)
  50. X    cc -o lptry $(OBJS) $(CDBOBJ)
  51. X
  52. Xinstall:    lptry
  53. X    strip lptry
  54. X    mv $(BIN)/lp $(BIN)/real_lp
  55. X    cpset lptry $(BIN) 0755
  56. X
  57. Xlint:    
  58. X    lint $(LINTFLAGS) $(SRC)
  59. X
  60. Xclean:
  61. X    /bin/rm -f *.o core
  62. X
  63. Xprint:    Makefile $(SRC)
  64. X    pr $? | $(LP)
  65. X    touch print
  66. SHAR_EOF
  67. if test 435 -ne "`wc -c < 'Makefile'`"
  68. then
  69.     echo shar: error transmitting "'Makefile'" '(should have been 435 characters)'
  70. fi
  71. fi # end of overwriting check
  72. echo shar: extracting "'README'" '(1519 characters)'
  73. if test -f 'README'
  74. then
  75.     echo shar: will not over-write existing file "'README'"
  76. else
  77. sed 's/^X//' << \SHAR_EOF > 'README'
  78. XThe standard lp(1) spooler in System V uses a variety of
  79. Xlockfiles in processing a job.  This leaves a window of
  80. Xvulnerability if two jobs are received nearly simultaneously:
  81. X
  82. X    lp job 1 checks to see if there is a lockfile,
  83. X        finds there isn't.
  84. X    lp job 2 checks to see if there is a lockfile,
  85. X        finds there isn't
  86. X    lp job 1 establishes the lockfile
  87. X    lp job 2 tries to establish the lockfile and fails.
  88. X
  89. XWhen this happens, the spooler croaks.  Often the symptom is
  90. Xthat jobs start piling up for printing but none ever are,
  91. Xsometimes it is more gory than that.  The fix is sometimes 
  92. Xto disable(1) the printer and then enable(1) it.  Sometimes 
  93. Xthe only fix is to cancel(1) the pending jobs.
  94. X
  95. XThis small program is another fix.  It moves /usr/bin/lp to
  96. X/usr/bin/real_lp, and subsitutes this program as /usr/bin/lp.
  97. XThus, you must be root to install the program.
  98. X
  99. XEssentially all this program does is throw up a semaphore,
  100. Xexecs real_lp, and lowers the semaphore.
  101. X
  102. XWe have been running this for two months without any failures
  103. Xor problems on an HP9000 Series 500 running Release 5.11 of
  104. XHP-UX (System V.2).  Because our application involves up to
  105. X200 one-page prints per day from 20 scattered users, prior to 
  106. Xits installation our spooler was hanging every couple of days 
  107. Xor so average with peaks of 2 or 3 hangs a day.
  108. X
  109. XYou may want to check ipcs(1) and ipcrm(1) if you are unfamiliar
  110. Xwith the System V semaphore facility.
  111. X--
  112. X    David Harrison, Dept. of Physics, Univ. of Toronto
  113. X    {ihnp4,utzoo}!utgpu!utfyzx!harrison
  114. SHAR_EOF
  115. if test 1519 -ne "`wc -c < 'README'`"
  116. then
  117.     echo shar: error transmitting "'README'" '(should have been 1519 characters)'
  118. fi
  119. fi # end of overwriting check
  120. echo shar: extracting "'lp.c'" '(2324 characters)'
  121. if test -f 'lp.c'
  122. then
  123.     echo shar: will not over-write existing file "'lp.c'"
  124. else
  125. sed 's/^X//' << \SHAR_EOF > 'lp.c'
  126. X#ifndef LINT
  127. Xstatic char SccsId[] = "@(#)lp.c    1.2 U of T Physics 12/16/87";
  128. X#endif
  129. X
  130. X/*
  131. X * This is an onionskin around the lp spooler.
  132. X * The problem is that the standard lp(1) uses lockfiles, with
  133. X * the well-known window of vulnerability between testing for
  134. X * the existence of the file and trying to create it.
  135. X * Thus, we have moved the standard lp command to "real_lp",
  136. X * and this program becomes "lp".
  137. X * It uses a semaphore to lock and unlock jobs sent to lp.
  138. X *        David Harrison - Dec/87
  139. X */
  140. X
  141. X#include <stdio.h>
  142. X#include <signal.h>
  143. X
  144. Xchar *real_lp_cmd = "real_lp";
  145. X
  146. Xchar *progname;
  147. X
  148. Xmain(argc, argv)
  149. Xint argc;
  150. Xchar *argv[];
  151. X{
  152. X    void _exit(), perror();
  153. X    char *emalloc();
  154. X    char *strcpy(), *strcat();
  155. X    char **exec_argv;
  156. X    int pid, w, status;
  157. X    int (*istat)(), (*qstat)();
  158. X    int i;
  159. X
  160. X    progname = argv[0];
  161. X
  162. X    /*
  163. X     * put arguments from argv into exec_argv, terminating
  164. X     * with a null.
  165. X     *
  166. X     * First malloc the array size needed ( with one for the NULL
  167. X     * and the end).
  168. X     */
  169. X    exec_argv = 
  170. X        (char **) emalloc( (unsigned) ((argc + 1) * sizeof (char *) ));
  171. X    /*
  172. X     * Put real_lp_cmd in argv[0]
  173. X     */
  174. X    exec_argv[0] = emalloc( (unsigned) (strlen(real_lp_cmd) + 1) );
  175. X    (void) strcpy(exec_argv[0], real_lp_cmd);
  176. X    /*
  177. X     * Now the other argements
  178. X     */
  179. X    if( argc > 1) {
  180. X        for(i = 1; i < argc; i++) {
  181. X            exec_argv[i] = emalloc( (unsigned) (strlen(argv[i]) + 1 ));
  182. X            (void) strcpy(exec_argv[i], argv[i]);
  183. X        }
  184. X    }
  185. X    /*
  186. X     * Terminate with a NULL
  187. X     */
  188. X    exec_argv[argc] = NULL;
  189. X
  190. X    lockproc();
  191. X
  192. X    switch( (pid = fork()) ) {
  193. X
  194. X        case -1:
  195. X            unlockproc();
  196. X            Sys_Error("Can't fork\n");
  197. X            break;
  198. X
  199. X        case 0:
  200. X            execvp( real_lp_cmd , exec_argv );
  201. X            unlockproc();
  202. X            fprintf(stderr,"%s: can't exec %s\n", 
  203. X                progname, real_lp_cmd );
  204. X            perror("exec");
  205. X            _exit(127);
  206. X
  207. X        default:
  208. X            break;
  209. X            
  210. X    }
  211. X
  212. X    /*
  213. X     * Trap signals and wait for child to finish.
  214. X     */
  215. X    istat = signal(SIGINT, SIG_IGN);
  216. X    qstat = signal(SIGQUIT, SIG_IGN);
  217. X    while( (w = wait(&status)) != pid && w != -1)
  218. X        ;
  219. X    if( w == -1)
  220. X        status = -1;
  221. X    signal(SIGINT, istat);
  222. X    signal(SIGQUIT, qstat);
  223. X
  224. X    unlockproc();
  225. X            
  226. X    return status;
  227. X
  228. X}
  229. X
  230. Xchar *
  231. Xemalloc(n)
  232. Xunsigned n;
  233. X{
  234. X    char *p, *malloc();
  235. X
  236. X    p = malloc(n);
  237. X    if ( p == 0)
  238. X        Sys_Error("Out of memory");
  239. X    return p;
  240. X}
  241. X
  242. XSys_Error(s)
  243. Xchar *s;
  244. X{
  245. X    void exit(), perror();
  246. X
  247. X    fprintf(stderr,"%s: %s\n",progname, s);
  248. X    perror("terminating");
  249. X    exit(1);
  250. X
  251. X}
  252. SHAR_EOF
  253. if test 2324 -ne "`wc -c < 'lp.c'`"
  254. then
  255.     echo shar: error transmitting "'lp.c'" '(should have been 2324 characters)'
  256. fi
  257. fi # end of overwriting check
  258. echo shar: extracting "'lock.c'" '(2776 characters)'
  259. if test -f 'lock.c'
  260. then
  261.     echo shar: will not over-write existing file "'lock.c'"
  262. else
  263. sed 's/^X//' << \SHAR_EOF > 'lock.c'
  264. X#ifndef LINT
  265. Xstatic char SccsId[] = "@(#)lock.c    1.1 U of T Physics 12/15/87";
  266. X#endif
  267. X
  268. X/*
  269. X * Standard lp creates lockfiles to suspend a second request.
  270. X * This leaves a small window of vulnerability if 2 users
  271. X * are using the program at one time.
  272. X *
  273. X * This file contains:
  274. X *    lockproc() - which locks so other user can use
  275. X *            the program.
  276. X *    unlockproc() - which unlocks for other users.
  277. X *
  278. X * It uses the semaphore facility and is highly system dependent.
  279. X */
  280. X
  281. X#include <stdio.h>
  282. X#include <sys/types.h>
  283. X#include <sys/ipc.h>
  284. X#include <sys/sem.h>
  285. X#include <errno.h>
  286. X
  287. X/*
  288. X * The following are the way to get a key out of ftok()
  289. X */
  290. X#define PATH     "/usr/bin/real_lp"
  291. X#define ID    'a'
  292. X
  293. X#define UNLOCK    (1)
  294. X#define LOCK    (-1)    /* impossible, so will lock */
  295. X
  296. X#define MODE    (0666)  /* rw by the world */
  297. X
  298. X/*
  299. X * If the owner removes the facility while a 2nd process is 
  300. X * waiting to lock it, the second process will receive an
  301. X * error from semop(2).  Thus, we try TRIES times to lock
  302. X * the process.
  303. X */
  304. X#define TRIES    5    
  305. X
  306. X#define YES    1
  307. X#define NO    0
  308. X
  309. Xstatic int sid;        /* semaphore id number */
  310. Xstatic short creator;    /* == YES if this process created */
  311. X
  312. Xextern char *progname;
  313. X
  314. Xlockproc()
  315. X{
  316. X    int sem_flg, numbad;
  317. X    key_t key, ftok();
  318. X    struct sembuf sb;
  319. X
  320. X    numbad = 0;
  321. X
  322. Xretry:
  323. X
  324. X    if((key = ftok(PATH,ID)) == -1) 
  325. X        Lock_Error("Cannot get ipc key");
  326. X
  327. X
  328. X    errno = 0;
  329. X    creator = NO;
  330. X
  331. X    if(numbad >= TRIES) {
  332. X        if(creator == YES)
  333. X            semctl(sid, IPC_RMID, 0);
  334. X        Lock_Error("Lock error");
  335. X    }
  336. X
  337. X    sem_flg = MODE | IPC_CREAT | IPC_EXCL;
  338. X
  339. X    sid = semget(key, 1, sem_flg);
  340. X    if(sid == -1 && errno == EEXIST) {
  341. X        /*
  342. X         * In use by another user.
  343. X         */
  344. X        sem_flg = MODE;
  345. X        (void) fflush(stdout);
  346. X        sid = semget(key, 1, sem_flg);
  347. X        /* it will get here, but then block */
  348. X    } else {
  349. X        creator = YES;
  350. X        if(semctl(sid, 0, SETVAL, UNLOCK) == -1) {
  351. X            semctl(sid, 0, IPC_RMID, 0);
  352. X            Lock_Error("Cannot create semaphore");
  353. X        }
  354. X    }
  355. X
  356. X    sb.sem_num = 0;        /* 1st semaphore */
  357. X    sb.sem_op = LOCK;    /* we are locking the semaphore */
  358. X    sb.sem_flg = SEM_UNDO;    /* auto reverse */
  359. X
  360. X    if (semop(sid, &sb, 1) == -1) {
  361. X        if( errno == EINTR || errno == EIDRM) {
  362. X            numbad++;
  363. X            goto retry;
  364. X        } else {
  365. X            Lock_Error("Cannot semop()");
  366. X        }
  367. X    }
  368. X}
  369. X
  370. Xunlockproc()
  371. X{
  372. X    struct sembuf sb;
  373. X
  374. X    if(creator == YES) {
  375. X        if(semctl(sid, IPC_RMID, 0) != 0) {
  376. X            Lock_Error("Cannot remove lock");
  377. X        }
  378. X    } else {
  379. X        sb.sem_num = 0;
  380. X        sb.sem_op = UNLOCK;
  381. X        sb.sem_flg = SEM_UNDO;
  382. X
  383. X        if(semop(sid, &sb, 1) == -1)
  384. X            Lock_Error("Cannot unlock");
  385. X    }
  386. X}
  387. X
  388. XLock_Error(s)
  389. Xchar *s;
  390. X{
  391. X    void exit();
  392. X    extern char *progname;
  393. X
  394. X    fprintf(stderr,"%s: please notify your system administrator\n",
  395. X        progname);
  396. X    fprintf(stderr,"that you received the following error message:\n");
  397. X    fprintf(stderr," ***** %s *****\n", s);
  398. X    fprintf(stderr,"Your print job has aborted.\n");
  399. X    exit(1);
  400. X}
  401. SHAR_EOF
  402. if test 2776 -ne "`wc -c < 'lock.c'`"
  403. then
  404.     echo shar: error transmitting "'lock.c'" '(should have been 2776 characters)'
  405. fi
  406. fi # end of overwriting check
  407. #    End of shell archive
  408. exit 0
  409.